package com.qp.basics.estivate.jdbc.datasource;

import com.qp.basics.estivate.Database;
import com.qp.basics.estivate.Session;
import com.qp.basics.estivate.transaction.TransactionDefinition;
import com.qp.basics.estivate.transaction.TransactionException;
import com.qp.basics.estivate.transaction.TransactionManager;
import com.qp.basics.estivate.transaction.support.DefaultTransactionStatus;
import com.qp.basics.estivate.transaction.support.TransactionSynchronizationManager;

import java.sql.Connection;
import java.sql.SQLException;

public class SessionTransactionManager extends TransactionManager {

	private Database database;

	public SessionTransactionManager(Database database) {
		this.database = database;
	}

	public Object doGetTransaction() {
		SessionTransactionObject txObject = new SessionTransactionObject();
		SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager
				.getResource(database);
		txObject.setSessionHolder(sessionHolder, false);
		return txObject;
	}

	public void doBegin(Object transactionObject,
			TransactionDefinition definition) {
		SessionTransactionObject txObject = (SessionTransactionObject) transactionObject;
		Connection connection = null;
		try {
			if (null == txObject.getSessionHolder()) {
				Session session = database.openSession();
				txObject.setSessionHolder(new SessionHolder(session), true);
			}

			connection = txObject.getSessionHolder().getSession()
					.getConnection();

			if (connection.getAutoCommit()) {
				connection.setAutoCommit(false);
			}

			txObject.getSessionHolder().setTransactionActive(true);
			if (txObject.isNewSessionHolder()) {
				TransactionSynchronizationManager.bindResource(database,
						txObject.getSessionHolder());
			}
		} catch (SQLException ex) {
			SessionUtils.releaseSession(txObject.getSessionHolder()
					.getSession(), database);
			throw new TransactionException("无法在事务中打开连接");
		}
	}

	public void doRollback(DefaultTransactionStatus status) {
		SessionTransactionObject txObject = (SessionTransactionObject) status
				.getTransactionObject();
		Connection connection = txObject.getSessionHolder().getSession()
				.getConnection();
		try {
			connection.rollback();
		} catch (SQLException ex) {
			throw new TransactionException("不能回滚事务", ex);
		}
	}

	public void doCommit(DefaultTransactionStatus status) {
		SessionTransactionObject txObject = (SessionTransactionObject) status
				.getTransactionObject();
		Connection connection = txObject.getSessionHolder().getSession()
				.getConnection();
		try {
			connection.commit();
		} catch (SQLException ex) {
			throw new TransactionException("不能提交事务", ex);
		}
	}

	public void doCleanupAfterCompletion(Object transactionObject) {
		SessionTransactionObject txObject = (SessionTransactionObject) transactionObject;
		if (txObject.isNewSessionHolder()) {
			TransactionSynchronizationManager.unbindResource(this.database);
			SessionHolder sessionHolder = txObject.getSessionHolder();
			SessionUtils.releaseSession(sessionHolder.getSession(), database);
		}
		txObject.getSessionHolder().clear();
	}

	protected boolean isExistingTransaction(Object transactionObject) {
		SessionTransactionObject txObject = (SessionTransactionObject) transactionObject;
		return (txObject.getSessionHolder() != null && txObject
				.getSessionHolder().isTransactionActive());
	}

	private static class SessionTransactionObject {

		private boolean newSessionHolder;
		private SessionHolder sessionHolder;

		public void setSessionHolder(SessionHolder sessionHolder,
				boolean newSessionHolder) {
			this.sessionHolder = sessionHolder;
			this.newSessionHolder = newSessionHolder;
		}

		public boolean isNewSessionHolder() {
			return newSessionHolder;
		}

		public boolean hasTransaction() {
			return (getSessionHolder() != null && getSessionHolder()
					.isTransactionActive());
		}

		public SessionHolder getSessionHolder() {
			return this.sessionHolder;
		}

	}
}
